package com.party.core.service.logistics.biz;

import com.google.common.collect.Maps;
import com.party.api.dto.logistics.request.RequestInput;
import com.party.api.dto.logistics.response.LogisticsResponse;
import com.party.api.dto.logistics.response.Traces;
import com.party.api.service.logistics.ILogisticsService;
import com.party.common.utils.DateUtils;
import com.party.common.utils.StringUtils;
import com.party.core.model.logistics.*;
import com.party.core.model.mall.MallOrderDetail;
import com.party.core.service.logistics.*;
import com.party.core.service.mall.IMallOrderDetailService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.text.ParseException;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 物流业务
 * Created by yifeng
 *
 * @date 2018/4/23 0023
 * @time 下午 16:44
 */
@Service
public class LogisticsBizService {
    @Autowired
    private IWlLogisticsService wlLogisticsService;
    @Autowired
    private IWlParcelService wlParcelService;
    @Autowired
    private IWlParcelTargetService wlParcelTargetService;
    @Autowired
    private IWlExpressService wlExpressService;
    @Autowired
    private IMallOrderDetailService mallOrderDetailService;
    @Autowired
    private ILogisticsService logisticsService;
    @Autowired
    private IWlLogisticsTraceService wlLogisticsTraceService;

    /**
     * 发货
     *
     * @param shipmentInput 发货参数
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public WlLogistics doShipmentInsert(ShipmentInput shipmentInput) {
        // 插入包裹
        String parcelId = this.insertParcel(shipmentInput.getTargetId(), shipmentInput.getType());
        // 插入包裹和物品的关系
        this.insertParcelTarget(shipmentInput.getGoodsTargetIds(), shipmentInput.getType(), parcelId);
        // 插入物流信息
        WlLogistics logistics = this.insertLogistics(shipmentInput.getCourierName(),
                shipmentInput.getCourierCode(), shipmentInput.getCourierNumber(), parcelId);

        this.updateExpressUseCount(shipmentInput.getCourierCode());
        return logistics;
    }

    /**
     * 保存物流信息
     *
     * @param courierName   快递公司名称
     * @param courierCode   快递公司编码
     * @param courierNumber 快递单号
     * @param parcelId      包裹id
     * @return
     */
    public WlLogistics insertLogistics(String courierName, String courierCode, String courierNumber, String parcelId) {
        WlLogistics logistics = new WlLogistics();
        logistics.setCourierName(courierName);
        logistics.setCourierCode(courierCode);
        logistics.setCourierNumber(courierNumber);
        logistics.setParcelId(parcelId);
        logistics.setStatus(WlLogisticsStatus.SHIPMENT.getCode());
        wlLogisticsService.insert(logistics);
        return logistics;
    }

    /**
     * 保存包裹信息
     *
     * @param targetId 业务id
     * @param type     业务类型
     * @return
     */
    public String insertParcel(String targetId, Integer type) {
        WlParcel parcel = new WlParcel();
        parcel.setTargetId(targetId);
        parcel.setType(type);
        Integer sort = wlParcelService.getCountByTargetId(targetId) + 1;
        parcel.setSort(sort);
        return wlParcelService.insert(parcel);
    }

    /**
     * 保存包裹和物品关系
     *
     * @param goodsTargetIds 物品IDS
     * @param type           类型
     * @param parcelId       包裹id
     */
    public void insertParcelTarget(String goodsTargetIds, Integer type, String parcelId) {
        for (String targetId : goodsTargetIds.split(",")) {
            String pic = "";
            Integer quantity = 1;
            if (type.equals(WlTargetType.MALL.getCode())) { // 商城
                MallOrderDetail orderDetail = mallOrderDetailService.get(targetId);
                pic = orderDetail.getPic();
                quantity = orderDetail.getQuantity();
            }
            WlParcelTarget parcelTarget = new WlParcelTarget();
            parcelTarget.setParcelId(parcelId);
            parcelTarget.setTargetId(targetId);
            parcelTarget.setType(type);
            parcelTarget.setPic(pic);
            parcelTarget.setQuantity(quantity);
            wlParcelTargetService.insert(parcelTarget);
        }
    }

    /**
     * 修改发货信息
     *
     * @param parcels     包裹信息
     * @param apiKey      apiKey
     * @param eBusinessID eBusinessID
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateShipment(List<ShipmentInput.ParcelOutput> parcels, String apiKey, String eBusinessID) throws Exception {
        for (ShipmentInput.ParcelOutput output : parcels) {
            if (StringUtils.isEmpty(output.getLogisticsId())) {
                throw new Exception("物流编号不能为空");
            }
            WlLogistics logistics = wlLogisticsService.get(output.getLogisticsId());
            logistics.setCourierNumber(output.getCourierNumber());
            logistics.setCourierCode(output.getCourierCode());
            logistics.setCourierName(output.getCourierName());
            wlLogisticsService.update(logistics);

            wlLogisticsTraceService.deleteByLogisticsId(logistics.getId());

            this.updateExpressUseCount(output.getCourierCode());

            this.subscribe(logistics, output.getTargetId(), apiKey, eBusinessID);
        }
    }

    /**
     * 修改发货信息
     *
     * @param shipmentInput 包裹信息
     */
    public void updateGiftShipment(ShipmentInput shipmentInput) {
        WlLogistics logistics = wlLogisticsService.get(shipmentInput.getLogisticsId());
        logistics.setCourierNumber(shipmentInput.getCourierNumber());
        logistics.setCourierCode(shipmentInput.getCourierCode());
        logistics.setCourierName(shipmentInput.getCourierName());
        wlLogisticsService.update(logistics);
    }

    /**
     * 更新快递公司的使用次数
     *
     * @param code
     */
    public void updateExpressUseCount(String code) {
        WlExpress wlExpress = wlExpressService.findByCode(code);
        // 增加使用数
        if (wlExpress.getUsingCount() == null) {
            wlExpress.setUsingCount(1);
        } else {
            wlExpress.setUsingCount(wlExpress.getUsingCount() + 1);
        }
        wlExpressService.update(wlExpress);

        wlExpressService.pushRedis();
    }

    /**
     * 根据业务id获取包裹信息
     *
     * @param
     * @return
     */
    public List<WlParcelOutput> findParcelByTargetId(String targetId) {
        List<WlParcelOutput> parcels = wlParcelService.findParcelByTargetId(targetId);
        for (WlParcelOutput output : parcels) {
            String value = WlLogisticsStatus.getValue(output.getStatus());
            output.setStatusName(value);
        }
        return parcels;
    }

    /**
     * 获取物流信息
     *
     * @param parcelOutput 物流信息
     * @param apiKey       apiKey
     * @param eBusinessId  eBusinessId
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public List<WlLogisticsTrace> getLogisticsTraces(WlParcelOutput parcelOutput, String apiKey, String eBusinessId) throws Exception {
        String logisticsId = parcelOutput.getLogisticsId();
        // 读取数据库是否存储物流信息
        List<WlLogisticsTrace> logisticsTraces = wlLogisticsTraceService.findByLogisticsId(logisticsId);
        try {
            if (CollectionUtils.isEmpty(logisticsTraces)) {
                WlLogistics logistics = wlLogisticsService.get(logisticsId);

                RequestInput input = new RequestInput();
                input.setApiKey(apiKey);
                input.seteBusinessID(eBusinessId);
                input.setCourierCode(logistics.getCourierCode());
                input.setCourierNumber(logistics.getCourierNumber());
                LogisticsResponse logisticsResponse = logisticsService.getLogisticsInfo(input);
                if (logisticsResponse != null) {
                    for (Traces traces : logisticsResponse.getTraces()) {
                        WlLogisticsTrace logisticsTrace = insertTrace(logistics.getId(), traces);
                        logisticsTraces.add(logisticsTrace);
                    }
                    WlLogistics mallLogistics = wlLogisticsService.get(logistics.getId());
                    if (StringUtils.isNotEmpty(logisticsResponse.getState())) {
                        mallLogistics.setStatus(Integer.valueOf(logisticsResponse.getState()));
                    }
                    if (StringUtils.isNotEmpty(logisticsResponse.getStateEx())) {
                        mallLogistics.setStatusEx(Integer.valueOf(logisticsResponse.getStateEx()));
                    }
                    mallLogistics.setLocation(logisticsResponse.getLocation());
                    wlLogisticsService.update(mallLogistics);

                    parcelOutput.setStatus(mallLogistics.getStatus());
                }
            }

            Collections.sort(logisticsTraces, (o1, o2) -> {
                try {
                    long time1 = DateUtils.parse(o1.getAcceptTime()).getTime();
                    long time2 = DateUtils.parse(o2.getAcceptTime()).getTime();
                    return time1 > time2 ? -1 : 1;
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                return 0;
            });
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new Exception("保存物流追踪信息异常");
        }
        return logisticsTraces;
    }

    /**
     * 保存物流追踪信息
     *
     * @param logisticsId 物流信息编号
     * @param traces      追踪信息
     * @return
     */
    public WlLogisticsTrace insertTrace(String logisticsId, Traces traces) {
        WlLogisticsTrace logisticsTrace = new WlLogisticsTrace();
        logisticsTrace.setLogisticsId(logisticsId);
        logisticsTrace.setAcceptTime(traces.getAcceptTime());
        logisticsTrace.setAcceptStation(traces.getAcceptStation());
        logisticsTrace.setRemark(traces.getRemark());
        logisticsTrace.setAction(traces.getAction());
        logisticsTrace.setLocation(traces.getLocation());
        wlLogisticsTraceService.insert(logisticsTrace);
        return logisticsTrace;
    }

    /**
     * 根据包裹id获取详情
     *
     * @param parcelId    包裹id
     * @param apiKey      apiKey
     * @param eBusinessId eBusinessId
     * @return
     */
    public Map<String, Object> findLogisticsById(String parcelId, String apiKey, String eBusinessId) throws Exception {
        Map<String, Object> resultMap = Maps.newHashMap();
        WlParcelOutput parcelOutput = wlParcelService.findByParcelId(parcelId);
        List<WlLogisticsTrace> logisticsTraces = this.getLogisticsTraces(parcelOutput, apiKey, eBusinessId);
        String value = WlLogisticsStatus.getValue(parcelOutput.getStatus());
        parcelOutput.setStatusName(value);
        resultMap.put("parcel", parcelOutput);
        resultMap.put("traces", logisticsTraces);
        return resultMap;
    }

    /**
     * 根据业务id获取物流信息
     *
     * @param targetId 业务id
     * @return
     */
    public Map<String, Object> findByTargetId(String targetId) {
        Map<String, Object> resultMap = Maps.newHashMap();
        List<WlParcelOutput> parcelOutputs = wlParcelService.findByTargetId(targetId);
        if (parcelOutputs.size() > 1) { // 有多个包裹
            Integer signedCount = wlParcelService.findByStatus(WlLogisticsStatus.HAVE_SIGNED.getCode(), targetId);
            resultMap.put("signedCount", signedCount); // 已签收数量
        } else if (parcelOutputs.size() == 1) { // 只有一个包裹
            WlParcelOutput parcelOutput = parcelOutputs.get(0);
            String logisticsId = parcelOutput.getLogisticsId();
            WlLogisticsTrace wlLogisticsTrace = wlLogisticsTraceService.getBestNewTrace(logisticsId);
            if (wlLogisticsTrace != null) {
                resultMap.put("acceptStation", wlLogisticsTrace.getAcceptStation());
                resultMap.put("acceptTime", wlLogisticsTrace.getAcceptTime());
            }
            resultMap.put("parcelId", parcelOutput.getParcelId());
        }
        resultMap.put("parcelCount", parcelOutputs.size()); // 包裹个数
        return resultMap;
    }

    /**
     * 轨迹订阅
     *
     * @param logistics   物流信息
     * @param orderId     订单id
     * @param apiKey      apiKey
     * @param eBusinessID eBusinessID
     */
    public void subscribe(WlLogistics logistics, String orderId, String apiKey, String eBusinessID) {
        RequestInput requestInput = new RequestInput();
        requestInput.setLogisticsId(logistics.getId());
        requestInput.setOrderId(orderId);
        requestInput.setCourierCode(logistics.getCourierCode());
        requestInput.setCourierNumber(logistics.getCourierNumber());
        requestInput.setApiKey(apiKey);
        requestInput.seteBusinessID(eBusinessID);
        logisticsService.traceSubscribe(requestInput);
    }

    /**
     * 根据业务id获取包裹
     *
     * @param targetId 业务id
     * @return
     */
    public WlParcelOutput getParcelByTargetId(String targetId) {
        List<WlParcelOutput> parcelOutputs = wlParcelService.findByTargetId(targetId);
        if (parcelOutputs.size() > 0) {
            return parcelOutputs.get(0);
        }
        return null;
    }
}
